package com.onlyxiahui.framework.net.session.server;

import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Locale;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Description <br>
 * Date 2019-04-27 08:15:10<br>
 * 
 * @author XiaHui [onlovexiahui@qq.com]<br>
 * @since 1.0.0
 */
public final class ThreadFactoryBuilder {

	private String nameFormat = null;
	private Boolean daemon = null;
	private Integer priority = null;
	private UncaughtExceptionHandler uncaughtExceptionHandler = null;
	private ThreadFactory backingThreadFactory = null;

	/**
	 * Creates a new {@link ThreadFactory} builder.
	 */
	public ThreadFactoryBuilder() {
	}

	/**
	 * 设置线程命名时使用的命名格式({@link Thread#setName}) 由这个ThreadFactory创建。
	 *
	 * @param nameFormat 一个{@link String#format(String, Object...)}兼容的
	 *                   格式化字符串，一个惟一的整数(0,1等)将格式化字符串 作为单个参数提供。这个整数是
	 *                   对于ThreadFactory和will的构建实例是惟一的 按顺序分配。例如,
	 *                   {@code "rpc-pool-%d"}将生成如下线程名 {@code“rpc-pool-0”},
	 *                   {@code rpc-pool-1 "}, {@code "rpc-pool-2"}等
	 * @return this
	 */
	public ThreadFactoryBuilder setNameFormat(String nameFormat) {
		// String unused = format(nameFormat, 0); // 如果格式不好或null，则快速失败
		// 如果格式不好或null，则快速失败
		format(nameFormat, 0); 
		this.nameFormat = nameFormat;
		return this;
	}

	/**
	 * 为这个ThreadFactory创建的新线程设置守护进程或不设置守护进程。
	 *
	 * @param daemon 守护进程，不管用这个ThreadFactory创建的新线程是否会 成为守护进程线程
	 * @return this
	 */
	public ThreadFactoryBuilder setDaemon(boolean daemon) {
		this.daemon = daemon;
		return this;
	}

	/**
	 * 设置使用这个ThreadFactory创建的新线程的优先级。
	 *
	 * @param priority 优先级使用这个ThreadFactory创建的新线程的优先级
	 * 
	 * 
	 * @return this
	 */
	public ThreadFactoryBuilder setPriority(int priority) {
		// Thread#setPriority() already checks for validity. These error messages
		// are nicer though and will fail-fast.
		checkArgument(
				priority >= Thread.MIN_PRIORITY,
				"Thread priority (%s) must be >= %s",
				priority,
				Thread.MIN_PRIORITY);
		checkArgument(
				priority <= Thread.MAX_PRIORITY,
				"Thread priority (%s) must be <= %s",
				priority,
				Thread.MAX_PRIORITY);
		this.priority = priority;
		return this;
	}

	public static void checkArgument(
			boolean expression,
			String errorMessageTemplate,
			Object... errorMessageArgs) {
		if (!expression) {
			throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageArgs));
		}
	}

	public static <T> T checkNotNull(T reference) {
		if (reference == null) {
			throw new NullPointerException();
		}
		return reference;
	}

	/**
	 * 为用它创建的新线程设置{@link UncaughtExceptionHandler} ThreadFactory。
	 *
	 * 未捕获的new异常处理程序 使用这个ThreadFactory创建的线程
	 *
	 * 
	 * @return this
	 */
	public ThreadFactoryBuilder setUncaughtExceptionHandler(
			UncaughtExceptionHandler uncaughtExceptionHandler) {
		this.uncaughtExceptionHandler = checkNotNull(uncaughtExceptionHandler);
		return this;
	}

	/**
	 * 为用它创建的新线程设置支持{@link ThreadFactory}
	 * ThreadFactory。将通过调用#newThread(Runnable)来创建线程 这个支持{@link ThreadFactory}。
	 *
	 * @param backingThreadFactory {@link ThreadFactory}将是 在线程创建期间委托给。
	 * @return this 返回构建器模式
	 * 
	 */
	public ThreadFactoryBuilder setThreadFactory(ThreadFactory backingThreadFactory) {
		this.backingThreadFactory = checkNotNull(backingThreadFactory);
		return this;
	}

	/**
	 * 使用构建期间提供的选项返回一个新的线程工厂 的过程。在构建之后，仍然可以更改以前使用的选项
	 * 构建ThreadFactory和/或再次构建。状态不会在构建之间共享 实例。
	 *
	 * @return ThreadFactory 完全构造 {@link ThreadFactory}
	 */
	public ThreadFactory build() {
		return build(this);
	}

	private static ThreadFactory build(ThreadFactoryBuilder builder) {
		final String nameFormat = builder.nameFormat;
		final Boolean daemon = builder.daemon;
		final Integer priority = builder.priority;
		final UncaughtExceptionHandler uncaughtExceptionHandler = builder.uncaughtExceptionHandler;
		final ThreadFactory backingThreadFactory = (builder.backingThreadFactory != null)
				? builder.backingThreadFactory
				: Executors.defaultThreadFactory();
		final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null;
		return new ThreadFactory() {
			@Override
			public Thread newThread(Runnable runnable) {
				Thread thread = backingThreadFactory.newThread(runnable);
				if (nameFormat != null) {
					thread.setName(format(nameFormat, count.getAndIncrement()));
				}
				if (daemon != null) {
					thread.setDaemon(daemon);
				}
				if (priority != null) {
					thread.setPriority(priority);
				}
				if (uncaughtExceptionHandler != null) {
					thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
				}
				return thread;
			}
		};
	}

	private static String format(String format, Object... args) {
		return String.format(Locale.ROOT, format, args);
	}
}
